; *******************************************************************
; * exp5_2.asm
; * LLP STUDIO Chen Zhepeng
; * V1.0
; * 2023-11-24
; * 定时器定时1 s，实现秒表功能（60归0）
; *******************************************************************

STACK_POINTER EQU  0D0H
SEG_A         BIT  P6.0
SEG_B         BIT  P6.1
SEG_C         BIT  P6.2
SEG_D         BIT  P6.3
SEG_E         BIT  P6.4
SEG_F         BIT  P6.5
SEG_G         BIT  P6.6
SEG_DP        BIT  P6.7
DISP_BLACK    EQU  10H
P0M1          DATA 0X93
P0M0          DATA 0X94
P1M1          DATA 0X91
P1M0          DATA 0X92
P2M1          DATA 0X95
P2M0          DATA 0X96
P3M1          DATA 0XB1
P3M0          DATA 0XB2
P4M1          DATA 0XB3
P4M0          DATA 0XB4
P5M1          DATA 0XC9
P5M0          DATA 0XCA
P6M1          DATA 0XCB
P6M0          DATA 0XCC
P7M1          DATA 0XE1
P7M0          DATA 0XE2
AUXR          DATA 8EH
P4            DATA 0C0H
P5            DATA 0C8H
P6            DATA 0E8H
P7            DATA 0F8H
; SFR定义
P_SW2         DATA 0BAH    ; 外设端口切换寄存器2
IRTRIM        DATA 09FH    ; IRC频率调整寄存器
; 系统时钟SFR定义
CKSEL         EQU  0FE00H  ; 时钟选择寄存器
CLKDIV        EQU  0FE01H  ; 时钟分频寄存器
HIRCCR        EQU  0FE02H  ; 内部高速振荡器控制寄存器
XOSCCR        EQU  0FE03H  ; 外部晶振控制寄存器
IRC32KCR      EQU  0FE04H  ; 内部32K振荡器控制寄存器
; IO口定义
P_HC595_SI    BIT  P4.4
P_HC595_SCK   BIT  P4.2
P_HC595_RCK   BIT  P4.3
; 使用变量定义
NIXIE8        DATA 30H
disp_index    DATA 38H
SECOND        DATA 39H

; 主程序
ORG 0000H
LJMP Main
ORG 000BH
LJMP Tm0Isr
ORG 0100H
Main:
CLR A
MOV P0M1, A
MOV P0M0, A
MOV P1M1, A
MOV P1M0, A
MOV P2M1, A
MOV P2M0, A
MOV P3M1, A
MOV P3M0, A
MOV P4M1, A
MOV P4M0, #01H
MOV P5M1, A
MOV P5M0, A
MOV P6M1, A
MOV P6M0, A
MOV P7M1, A
MOV P7M0, A
MOV SP, #STACK_POINTER
MOV PSW, #00H
SETB P4.0  ; 关闭LED灯显示
; 系统时钟分频器初始化
MOV P_SW2, #80H  ; 最高位EAXFR == 1，使能扩展RAM区特殊功能寄存器XFR访问
; 选择内部高速高精度IRC（24 MHz）
MOV A, #00H
MOV DPTR, #CKSEL
MOVX @DPTR, A
; 时钟2分频后为系统时钟SYSCLK == 12 MHz
MOV A, #02H
MOV DPTR, #CLKDIV
MOVX @DPTR, A
MOV P_SW2, #00H  ; 禁止访问XFR
MOV AUXR, #00H  ; 定时器定时脉冲来自系统时钟12分频
;ORL AUXR, #80H  ; 定时器定时脉冲来自系统时钟不分频
; 初始化程序
MOV disp_index, #0
MOV R0, #NIXIE8
MOV R2, #8
ClearLoop:
MOV @R0, #DISP_BLACK
INC R0
DJNZ R2, ClearLoop
MOV NIXIE8, #00H
MOV NIXIE8 + 1, #00H
MOV SECOND, #00H

MOV IE, #02H  ; 允许T0中断
MOV IP, #00H
MOV TMOD, #00H  ; T0工作在方式0的16位自动重新装载的定时器方式
; 延时50ms 65536 - 15536
MOV TH0, #3CH
MOV TL0, #0B0H
MOV R7, #20  ; 1秒计数器置初值
SETB TR0  ; 启动T0工作
SETB EA  ; 全局开放中断

; 主循环
MainLoop:
LCALL DisplayScan
LCALL Delay1ms
SJMP MainLoop

TableDisplay:
DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH
DB 6FH, 77H, 7CH, 39H, 5EH, 79H, 71H
DB 00H, 40H, 76H, 1EH, 70H, 38H, 37H, 5CH, 73H
DB 3EH, 78H, 3DH, 67H, 50H, 37H, 6EH

TableCom:
DB 01H, 02H, 04H, 08H, 10H, 20H, 40H, 80H

; 函数 Send595
Send595:
PUSH 02H
MOV R2, #8
Send595Loop:
RLC A
MOV P_HC595_SI, C
SETB P_HC595_SCK
CLR P_HC595_SCK
DJNZ R2, Send595Loop
POP 02H
RET

; 函数DisplayScan
DisplayScan:
PUSH DPH
PUSH DPL
PUSH 00H
CLR A
LCALL Send595
MOV DPTR, #TableCom
MOV A, disp_index
MOVC A, @A + DPTR
NOP
LCALL Send595
NOP
SETB P_HC595_RCK
CLR P_HC595_RCK
MOV DPTR, #TableDisplay
MOV A, disp_index
ADD A, #NIXIE8
MOV R0, A
MOV A, @R0
MOVC A, @A + DPTR
CPL A
MOV P6, A
INC disp_index
MOV A, disp_index
ANL A, #0F8H
JZ QuitDisplayScan
MOV disp_index, #0
QuitDisplayScan:
POP 00H
POP DPL
POP DPH
RET

; 定时器T0 中断服务子程序
Tm0Isr:
PUSH ACC
PUSH PSW

DJNZ R7, NEXT1
MOV R7, #20
MOV A, SECOND
ADD A, #01H
DA A
CJNE A, #60H, IncSec
MOV A, #00H  ; 如果60 s到，从00开始重新显示
IncSec:
MOV SECOND, A

MOV A, SECOND
ANL A, #0FH
MOV NIXIE8, A
MOV A, SECOND
ANL A, #0F0H
SWAP A
MOV NIXIE8 + 1, A

NEXT1:
POP PSW
POP ACC
RETI

;延时子程序（下载频率为24.000MHz）
Delay1ms:	PUSH	03H
			PUSH	04H
			MOV	R3,#40
			MOV	R4,#249
NEXT:		DJNZ	R4, NEXT
			DJNZ	R3, NEXT
			NOP
			NOP
			POP		04H
			POP		03H
			RET

END
